import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:xuance/bean/HomeAiWarnBean.dart';
import 'package:xuance/bean/HomeBlockIpBean.dart';
import 'package:xuance/bean/MidChartbean.dart';
import 'package:xuance/bean/TimeCountBean.dart';
import 'package:xuance/bean/TimeEnum.dart';
import 'package:xuance/constant.dart';
import 'package:xuance/util/common_util.dart';

class ChartUtil {
  static LineChartData blockIpLineChart(
      {LineTouchData lineTouchData = const LineTouchData(),
      required List<HomeBlockIpBean> data,
      required TimeEnum dateType}) {
    List<TimeCountBean> result = [];
    int periodCount = 30;
    DateTime now = DateTime.now();
    periodCount = dateType.period;
    result =
        List.generate(periodCount, (_) => TimeCountBean(time: '', count: 0));
    for (var bean in data) {
      DateTime warnDate =
          string2Date("${bean.blockedTime}", pattern: "yyyy-MM-dd HH:mm")!;
      int index = -1;
      switch (dateType) {
        case TimeEnum.hour:
          index = now.difference(warnDate).inMinutes;
          if (index >= 0 && index < 60) {
            result[59 - index].time = warnDate.toIso8601String();
            result[59 - index].count += int.tryParse('${bean.nums}') ?? 0;
          }
          break;
        case TimeEnum.day:
          index = now.difference(warnDate).inHours;
          if (index >= 0 && index < 24) {
            result[23 - index].time = warnDate.toIso8601String();
            result[23 - index].count += int.tryParse('${bean.nums}') ?? 0;
          }
          break;
        case TimeEnum.week:
          index = now.difference(warnDate).inDays;
          if (index >= 0 && index < 7) {
            result[6 - index].time = warnDate.toIso8601String();
            result[6 - index].count += int.tryParse('${bean.nums}') ?? 0;
          }
          break;
        case TimeEnum.month:
          index = now.difference(warnDate).inDays;
          if (index >= 0 && index < 30) {
            result[29 - index].time = warnDate.toIso8601String();
            result[29 - index].count += int.tryParse('${bean.nums}') ?? 0;
          }
          break;
      }
    }
    List<FlSpot> spots = [];
    double maxX = 0.0;
    double maxY = 0.0;

    maxX = result.length.toDouble();
    maxY = result
        .map((f) => f.count)
        .toList()
        .reduce((value, element) => value > element ? value : element)
        .toDouble();
    for (var m = 0; m < result.length; m++) {
      spots.add(FlSpot(
          m.toDouble() + 1, double.tryParse('${result[m].count}') ?? 0.0));
    }

    return LineChartData(
        lineTouchData: lineTouchData,
        gridData: FlGridData(
            show: true,
            drawVerticalLine: false,
            drawHorizontalLine: false,
            horizontalInterval: 1,
            verticalInterval: 1,
            getDrawingHorizontalLine: (value) {
              return const FlLine(strokeWidth: 1);
            },
            getDrawingVerticalLine: (value) {
              return const FlLine(strokeWidth: 1);
            }),
        titlesData: const FlTitlesData(
            show: true,
            rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
            topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
            bottomTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
            leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: false))),
        borderData: FlBorderData(show: false),
        minX: 0,
        maxX: maxX,
        minY: 0,
        maxY: maxY,
        lineBarsData: [
          LineChartBarData(
              spots: spots,
              isCurved: true,
              color: c_green,
              barWidth: 3,
              isStrokeCapRound: true,
              dotData: const FlDotData(show: false),
              belowBarData: BarAreaData(
                  show: true,
                  gradient: const LinearGradient(colors: [
                    Color.fromARGB(81, 39, 211, 149),
                    Color.fromARGB(0, 39, 211, 149)
                  ], begin: Alignment.topCenter, end: Alignment.bottomCenter)))
        ]);
  }

  static LineChartData warningLineChart(
      {LineTouchData lineTouchData = const LineTouchData(),
      required List<HomeAiWarnBean> data,
      required TimeEnum dateType}) {
    List<TimeCountBean> result = [];
    DateTime now = DateTime.now();
    result = List.generate(
        dateType.period, (_) => TimeCountBean(time: '', count: 0));
    for (var bean in data) {
      DateTime warnDate =
          string2Date("${bean.warnTime}", pattern: "yyyy-MM-dd HH:mm")!;
      int index = -1;
      switch (dateType) {
        case TimeEnum.hour:
          index = now.difference(warnDate).inMinutes;
          if (index >= 0 && index < 60) {
            result[59 - index].time = warnDate.toIso8601String();
            result[59 - index].count += int.tryParse('${bean.warnCount}') ?? 0;
          }
          break;
        case TimeEnum.day:
          index = now.difference(warnDate).inHours;
          if (index >= 0 && index < 24) {
            result[23 - index].time = warnDate.toIso8601String();
            result[23 - index].count += int.tryParse('${bean.warnCount}') ?? 0;
          }
          break;
        case TimeEnum.week:
          index = now.difference(warnDate).inDays;
          if (index >= 0 && index < 7) {
            result[6 - index].time = warnDate.toIso8601String();
            result[6 - index].count += int.tryParse('${bean.warnCount}') ?? 0;
          }
          break;
        case TimeEnum.month:
          index = now.difference(warnDate).inDays;
          if (index >= 0 && index < 30) {
            result[29 - index].time = warnDate.toIso8601String();
            result[29 - index].count += int.tryParse('${bean.warnCount}') ?? 0;
          }
          break;
      }
    }
    List<FlSpot> spots = [];
    double maxX = 0.0;
    double maxY = 0.0;

    maxX = result.length.toDouble();
    maxY = result
        .map((f) => f.count)
        .toList()
        .reduce((value, element) => value > element ? value : element)
        .toDouble();
    for (var m = 0; m < result.length; m++) {
      spots.add(FlSpot(
          m.toDouble() + 1, double.tryParse('${result[m].count}') ?? 0.0));
    }

    return LineChartData(
        lineTouchData: lineTouchData,
        gridData: FlGridData(
            show: true,
            drawVerticalLine: false,
            drawHorizontalLine: false,
            horizontalInterval: 1,
            verticalInterval: 1,
            getDrawingHorizontalLine: (value) {
              return const FlLine(strokeWidth: 1);
            },
            getDrawingVerticalLine: (value) {
              return const FlLine(strokeWidth: 1);
            }),
        titlesData: const FlTitlesData(
          show: true,
          rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
          topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
          bottomTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
          leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
        ),
        borderData: FlBorderData(show: false),
        minX: 0,
        maxX: maxX,
        minY: 0,
        maxY: maxY,
        lineBarsData: [
          LineChartBarData(
              spots: spots,
              isCurved: true,
              color: c_red,
              barWidth: 3,
              isStrokeCapRound: true,
              dotData: const FlDotData(show: false),
              belowBarData: BarAreaData(
                  show: true,
                  gradient: const LinearGradient(colors: [
                    Color.fromARGB(200, 175, 59, 56),
                    Colors.transparent
                  ], begin: Alignment.topCenter, end: Alignment.bottomCenter)))
        ]);
  }

  static LineChartData getMainMidChart(
      {required List<MidChartbean> low,
      required List<MidChartbean> mid,
      required List<MidChartbean> high,
      required TimeEnum type // 类型: hour, day, week, month
      }) {
    int maxX = 0;
    List<FlSpot> lowSpots = [];
    List<FlSpot> midSpots = [];
    List<FlSpot> highSpots = [];

    if (type == TimeEnum.hour) {
      maxX = 60; // 每分钟一个单位
    } else if (type == TimeEnum.day) {
      maxX = 24; // 每小时一个单位
    } else if (type == TimeEnum.week) {
      maxX = 7; // 每天一个单位
    } else if (type == TimeEnum.month) {
      maxX = 30; // 每天一个单位
    } else {
      maxX = 90;
    }

    // 创建一个用于记录每个时间单位的警告数量
    List<int> lowNums = List.filled(maxX, 0);
    List<int> midNums = List.filled(maxX, 0);
    List<int> highNums = List.filled(maxX, 0);

    // 处理 low, mid, high 数据
    List<MidChartbean> allData = [...low, ...mid, ...high];
    for (var item in allData) {
      var warningTime =
          string2Date('${item.warningTime}', pattern: "yyyy-MM-dd HH:mm")!;
      if (item.warningTime != null &&
          warningTime
              .isAfter(DateTime.now().subtract(const Duration(days: 30)))) {
        int timeIndex = 0;
        // 根据 type 计算时间索引
        if (type == TimeEnum.hour) {
          timeIndex = 59 - DateTime.now().difference(warningTime).inMinutes;
        } else if (type == TimeEnum.day) {
          timeIndex = 23 - DateTime.now().difference(warningTime).inHours;
        } else if (type == TimeEnum.week) {
          timeIndex = 6 - DateTime.now().difference(warningTime).inDays;
        } else if (type == TimeEnum.month) {
          timeIndex = 29 - DateTime.now().difference(warningTime).inDays;
        }
        // else if (type == TimeEnum.threeMonth) {
        //   timeIndex = 89 - DateTime.now().difference(warningTime).inDays;
        // }

        // 确保索引有效
        if (timeIndex >= 0 && timeIndex < maxX) {
          // 根据警告等级累加数量
          if (item.warningLevel == 'low') {
            lowNums[timeIndex] += item.warningSum?.toInt() ?? 0;
          } else if (item.warningLevel == 'medium') {
            midNums[timeIndex] += item.warningSum?.toInt() ?? 0;
          } else if (item.warningLevel == 'high') {
            highNums[timeIndex] += item.warningSum?.toInt() ?? 0;
          }
        }
      }
    }

    // 生成 spots 数据
    for (int i = 0; i < maxX; i++) {
      lowSpots.add(FlSpot(i.toDouble() + 1, lowNums[i].toDouble()));
      midSpots.add(FlSpot(i.toDouble() + 1, midNums[i].toDouble()));
      highSpots.add(FlSpot(i.toDouble() + 1, highNums[i].toDouble()));
    }

    int maxY = [
      ...lowSpots.map((e) => e.y.toInt()),
      ...midSpots.map((e) => e.y.toInt()),
      ...highSpots.map((e) => e.y.toInt())
    ].reduce((a, b) => a > b ? a : b);

    return LineChartData(
        gridData:
            const FlGridData(drawVerticalLine: true, drawHorizontalLine: true),
        titlesData: FlTitlesData(
            bottomTitles: AxisTitles(
                sideTitles: SideTitles(
                    showTitles: true,
                    interval: (maxX > 5 ? maxX ~/ 5 : 1).toDouble(),
                    getTitlesWidget: (value, meta) {
                      String title;
                      if (type == TimeEnum.hour) {
                        title = DateFormat('HH:mm').format(DateTime.now()
                            .subtract(Duration(minutes: maxX - value.toInt())));
                      } else if (type == TimeEnum.day) {
                        title = DateFormat('HH:00').format(DateTime.now()
                            .subtract(Duration(hours: maxX - value.toInt())));
                      } else if (type == TimeEnum.week) {
                        title = DateFormat('MM/dd').format(DateTime.now()
                            .subtract(Duration(days: maxX - value.toInt())));
                      } else {
                        title = DateFormat('MM/dd').format(DateTime.now()
                            .subtract(Duration(days: maxX - value.toInt())));
                      }
                      return Text(title,
                          style: TextStyle(fontSize: 8, color: c_9EA1A6),
                          textAlign: TextAlign.center);
                    })),
            rightTitles:
                const AxisTitles(sideTitles: SideTitles(showTitles: false)),
            topTitles:
                const AxisTitles(sideTitles: SideTitles(showTitles: false)),
            leftTitles: AxisTitles(
                sideTitles: SideTitles(
                    getTitlesWidget: (value, meta) {
                      return Text(
                        "${value.round()}",
                        style: TextStyle(fontSize: 8, color: c_9EA1A6),
                        textAlign: TextAlign.center,
                      );
                    },
                    showTitles: true))),
        borderData: FlBorderData(show: false),
        lineBarsData: [
          LineChartBarData(
              isCurved: false,
              color: c_red,
              barWidth: 2,
              isStrokeCapRound: true,
              dotData: const FlDotData(show: false),
              belowBarData: BarAreaData(show: false),
              spots: highSpots),
          LineChartBarData(
              isCurved: false,
              color: c_orange,
              barWidth: 2,
              isStrokeCapRound: true,
              dotData: const FlDotData(show: false),
              belowBarData: BarAreaData(show: false),
              spots: midSpots),
          LineChartBarData(
            isCurved: false,
            color: c_blue,
            barWidth: 2,
            isStrokeCapRound: true,
            dotData: const FlDotData(show: false),
            belowBarData: BarAreaData(show: false),
            spots: lowSpots,
          ),
        ],
        minX: 0,
        maxX: maxX.toDouble(),
        maxY: maxY.toDouble(),
        minY: 0);
  }

  static LineChartData getWarningChart(
      {required List<HomeAiWarnBean> blockips,
      required TimeEnum currentWarning}) {
    var now = DateTime.now();
    int maxX = currentWarning.period;
    List<FlSpot> spots = [];
    List<int> numsPerTimeUnit = List.filled(maxX, 0);
    for (var blockip in blockips) {
      if (blockip.warnTime != null &&
          string2Date("${blockip.warnTime}", pattern: "yyyy-MM-dd HH:mm")!
              .isAfter(now.subtract(const Duration(days: 30)))) {
        int timeIndex = 0;
        DateTime blockedTime =
            string2Date("${blockip.warnTime}", pattern: "yyyy-MM-dd HH:mm")!;
        if (currentWarning == TimeEnum.hour) {
          timeIndex =
              currentWarning.period - 1 - now.difference(blockedTime).inMinutes;
        } else if (currentWarning == TimeEnum.day) {
          timeIndex =
              currentWarning.period - 1 - now.difference(blockedTime).inHours;
        } else if (currentWarning == TimeEnum.week) {
          timeIndex =
              currentWarning.period - 1 - now.difference(blockedTime).inDays;
        } else if (currentWarning == TimeEnum.month) {
          timeIndex =
              currentWarning.period - 1 - now.difference(blockedTime).inDays;
        }
        if (timeIndex >= 0 && timeIndex < maxX) {
          numsPerTimeUnit[timeIndex] += blockip.warnCount?.toInt() ?? 0;
        }
      }
    }
    for (int i = 0; i < maxX; i++) {
      spots.add(FlSpot(i.toDouble() + 1, numsPerTimeUnit[i].toDouble()));
    }
    int maxY =
        spots.map((m) => m.y.toInt()).toList().reduce((a, b) => a > b ? a : b);

    return LineChartData(
        gridData:
            const FlGridData(drawVerticalLine: true, drawHorizontalLine: true),
        titlesData: FlTitlesData(
            bottomTitles: AxisTitles(
                sideTitles: SideTitles(
                    showTitles: true,
                    interval: (maxX > 5 ? maxX ~/ 5 : 1).toDouble(),
                    getTitlesWidget: (double value, TitleMeta meta) {
                      String title;
                      if (currentWarning == TimeEnum.hour) {
                        // 每分钟显示时间
                        title = DateFormat('HH:mm').format(DateTime.now()
                            .subtract(Duration(minutes: maxX - value.toInt())));
                      } else if (currentWarning == TimeEnum.day) {
                        // 每小时显示时间
                        title = DateFormat('HH:00').format(DateTime.now()
                            .subtract(Duration(hours: maxX - value.toInt())));
                      } else if (currentWarning == TimeEnum.week) {
                        // 每天显示日期
                        title = DateFormat('MM/dd').format(DateTime.now()
                            .subtract(Duration(days: maxX - value.toInt())));
                      } else {
                        // 每天显示日期
                        title = DateFormat('MM/dd').format(DateTime.now()
                            .subtract(Duration(days: maxX - value.toInt())));
                      }
                      return Text(title,
                          style: TextStyle(fontSize: 8, color: c_9EA1A6),
                          textAlign: TextAlign.center);
                    })),
            rightTitles:
                const AxisTitles(sideTitles: SideTitles(showTitles: false)),
            topTitles:
                const AxisTitles(sideTitles: SideTitles(showTitles: false)),
            leftTitles: AxisTitles(
                sideTitles: SideTitles(
                    interval: (maxY > 5 ? (maxY / 5).toDouble() : 1).toDouble(),
                    getTitlesWidget: (double value, TitleMeta meta) {
                      return Text("${value.toInt()}",
                          style: TextStyle(fontSize: 8, color: c_9EA1A6),
                          textAlign: TextAlign.center);
                    },
                    showTitles: true))),
        borderData: FlBorderData(show: false),
        lineBarsData: [
          LineChartBarData(
              isCurved: false,
              color: c_red,
              barWidth: 2,
              isStrokeCapRound: true,
              dotData: const FlDotData(show: false),
              belowBarData: BarAreaData(
                  show: true,
                  gradient: const LinearGradient(colors: [
                    Color.fromARGB(200, 175, 59, 56),
                    Colors.transparent
                  ], begin: Alignment.topCenter, end: Alignment.bottomCenter)),
              spots: spots)
        ],
        minX: 0,
        maxX: maxX.toDouble(),
        maxY: maxY.toDouble(),
        minY: 0);
  }

  static LineChartData getBanIpChart(
      {required List<HomeBlockIpBean> blockips,
      required TimeEnum currentWarning}) {
    int maxX = currentWarning.period;
    List<FlSpot> spots = [];
    List<int> numsPerTimeUnit = List.filled(maxX, 0);
    for (var blockip in blockips) {
      if (blockip.blockedTime != null &&
          string2Date("${blockip.blockedTime}", pattern: "yyyy-MM-dd HH:mm")!
              .isAfter(DateTime.now().subtract(const Duration(days: 30)))) {
        int timeIndex = 0;
        DateTime blockedTime =
            string2Date("${blockip.blockedTime}", pattern: "yyyy-MM-dd HH:mm")!;
        if (currentWarning == TimeEnum.hour) {
          timeIndex = currentWarning.period -
              1 -
              DateTime.now().difference(blockedTime).inMinutes;
        } else if (currentWarning == TimeEnum.day) {
          timeIndex = currentWarning.period -
              1 -
              DateTime.now().difference(blockedTime).inHours;
        } else if (currentWarning == TimeEnum.week) {
          timeIndex = currentWarning.period -
              1 -
              DateTime.now().difference(blockedTime).inDays;
        } else if (currentWarning == TimeEnum.month) {
          timeIndex = currentWarning.period -
              1 -
              DateTime.now().difference(blockedTime).inDays;
        }
        if (timeIndex >= 0 && timeIndex < maxX) {
          numsPerTimeUnit[timeIndex] += blockip.nums?.toInt() ?? 0;
        }
      }
    }
    for (int i = 0; i < maxX; i++) {
      spots.add(FlSpot(i.toDouble() + 1, numsPerTimeUnit[i].toDouble()));
    }
    int maxY =
        spots.map((m) => m.y.toInt()).toList().reduce((a, b) => a > b ? a : b);

    return LineChartData(
      gridData:
          const FlGridData(drawVerticalLine: true, drawHorizontalLine: true),
      titlesData: FlTitlesData(
          bottomTitles: AxisTitles(
              sideTitles: SideTitles(
                  showTitles: true,
                  interval: (maxX > 5 ? maxX ~/ 5 : 1).toDouble(),
                  getTitlesWidget: (double value, TitleMeta meta) {
                    String title;
                    if (currentWarning == TimeEnum.hour) {
                      // 每分钟显示时间
                      title = DateFormat('HH:mm').format(DateTime.now()
                          .subtract(Duration(minutes: maxX - value.toInt())));
                    } else if (currentWarning == TimeEnum.day) {
                      // 每小时显示时间
                      title = DateFormat('HH:00').format(DateTime.now()
                          .subtract(Duration(hours: maxX - value.toInt())));
                    } else if (currentWarning == TimeEnum.week) {
                      // 每天显示日期
                      title = DateFormat('MM/dd').format(DateTime.now()
                          .subtract(Duration(days: maxX - value.toInt())));
                    } else {
                      // 每天显示日期
                      title = DateFormat('MM/dd').format(DateTime.now()
                          .subtract(Duration(days: maxX - value.toInt())));
                    }
                    return Text(
                      title,
                      style: TextStyle(fontSize: 8, color: c_9EA1A6),
                      textAlign: TextAlign.center,
                    );
                  })),
          rightTitles:
              const AxisTitles(sideTitles: SideTitles(showTitles: false)),
          topTitles:
              const AxisTitles(sideTitles: SideTitles(showTitles: false)),
          leftTitles: AxisTitles(
              sideTitles: SideTitles(
                  interval: (maxY > 5 ? maxY ~/ 5 : 1).toDouble(),
                  getTitlesWidget: (double value, TitleMeta meta) {
                    return Text("$value",
                        style: TextStyle(fontSize: 8, color: c_9EA1A6),
                        textAlign: TextAlign.center);
                  },
                  showTitles: true))),
      borderData: FlBorderData(show: false),
      lineBarsData: [
        LineChartBarData(
          isCurved: true,
          color: c_green,
          barWidth: 2,
          isStrokeCapRound: true,
          dotData: const FlDotData(show: false),
          belowBarData: BarAreaData(
            show: true,
            gradient: const LinearGradient(
              colors: [
                Color.fromARGB(81, 39, 211, 149),
                Color.fromARGB(0, 39, 211, 149)
              ],
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
            ),
          ),
          spots: spots,
        ),
      ],
      minX: 0,
      maxX: maxX.toDouble(),
      maxY: maxY.toDouble(),
      minY: 0,
    );
  }
}
